package org.liuh.designs.spider.utils;

/**
 * @ClassName: HttpClientUtil
 * @Description: httpClientUtils
 * @Author: liuh
 * @Date: 2020/10/10 11:26
 * @Version: 1.0
 */

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.params.CookiePolicy;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.impl.client.*;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.liuh.designs.spider.dtos.ProxyEo;

import java.io.IOException;
import java.net.CookieManager;
import java.net.CookieStore;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @Description: httpClient连接池
 * @Author: liuh
 * @Date: 2020/10/10
 */
public class HttpClientUtil {
    // 初始化代理Ip..
    public static PoolingHttpClientConnectionManager connectionManager = null;
    public static AtomicInteger getCountAtomic = new AtomicInteger(0);
    private static final Map<Integer, ProxyEo> IP_MAP = new HashMap<>(100);
    private static CloseableHttpClient httpClient = null;
    private static ProxyEo proxyEo = null;

    static {
        if (IP_MAP.isEmpty()) {
            initIpMap();
        }
        // default: 100
//        resetProxyIP(100, 100);
    }

    public static void initIpMap() {
        //TODO 2020.10.12 有效代理..
//        IP_MAP.put(0, new ProxyEo("39.108.158.213", 8888));
        IP_MAP.put(0, new ProxyEo("211.137.52.158", 8080));
        IP_MAP.put(1, new ProxyEo("113.121.39.47", 9999));
        IP_MAP.put(2, new ProxyEo("121.40.138.182", 8080));
    }

    /**
     * @Description: 重新设置代理IP..
     * @Author: liuh
     * @Date: 2020/10/10
     */
    public static void resetProxyIP(int maxTotal, int singleTotal) {
        connectionManager = new PoolingHttpClientConnectionManager();
        // 总连接池数量
        connectionManager.setMaxTotal(maxTotal);
        int num = RandomUtils.getRandomNumber(IP_MAP.size());
        ProxyEo proxyEo = IP_MAP.get(num);
        System.out.println(String.format("切换ProxyIP, getCountAtomic: %s, 代理IP： %s, Port: %s", getCountAtomic.get(), proxyEo.getIpAddr(), proxyEo.getPort()));
        // 可为每个域名设置单独的连接池数量
        connectionManager.setMaxPerRoute(new HttpRoute(new HttpHost("www.stats.gov.cn")), singleTotal);
        connectionManager.setDefaultMaxPerRoute(maxTotal);
        // setConnectTimeout：设置建立连接的超时时间
        // setConnectionRequestTimeout：从连接池中拿连接的等待超时时间
        // setSocketTimeout：发出请求后等待对端应答的超时时间
        RequestConfig requestConfig = RequestConfig.custom()
//                .setProxy(new HttpHost(proxyEo.getIpAddr(), proxyEo.getPort()))
                .setConnectTimeout(200000)
                .setConnectionRequestTimeout(200000)
                .setSocketTimeout(200000)
                .setRedirectsEnabled(false)
                .setCookieSpec(CookieSpecs.STANDARD)
                .build();
        // 重试处理器，StandardHttpRequestRetryHandler
        HttpRequestRetryHandler retryHandler = new StandardHttpRequestRetryHandler();
        httpClient = HttpClients.custom().setConnectionManager(connectionManager).setDefaultRequestConfig(requestConfig).setRetryHandler(retryHandler).build();
    }

    /**
     * @Description: 调用http请求..
     * @Author: liuh
     * @Date: 2020/10/10
     */
    public static String doHttpGet(String uri, String sourceUrl, Map<String, String> getParams, String charset) {
        CloseableHttpResponse response = null;
        try {
            // 每200个请求切换一次代理host..
            URIBuilder uriBuilder = new URIBuilder(uri);
            if (null != getParams && !getParams.isEmpty()) {
                List<NameValuePair> list = new ArrayList<>();
                for (Map.Entry<String, String> param : getParams.entrySet()) {
                    list.add(new BasicNameValuePair(param.getKey(), param.getValue()));
                }
                uriBuilder.setParameters(list);
            }
            HttpGet httpGet = getHttpGet(sourceUrl, uriBuilder.build().toString());
            response = httpClient.execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();
            if (HttpStatus.SC_OK == statusCode) {
                HttpEntity entity = response.getEntity();
                if (null != entity) {
                    String resStr = EntityUtils.toString(entity, charset);
                    return resStr;
                }
            }
        } catch (ConnectTimeoutException e1) {
            // 重试..
//            HttpClientUtil.resetProxyIP();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                // +1..
                getCountAtomic.incrementAndGet();
                if (null != response) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * @Description: port处理..
     * @Author: liuh
     * @Date: 2020/10/10
     */
    public static String doHttpPost(String uri, Map<String, String> getParams, String charset) {
        CloseableHttpResponse response = null;
        try {
            HttpPost httpPost = new HttpPost(uri);
            if (null != getParams && !getParams.isEmpty()) {
                List<NameValuePair> list = new ArrayList<>();
                for (Map.Entry<String, String> param : getParams.entrySet()) {
                    list.add(new BasicNameValuePair(param.getKey(), param.getValue()));
                }
                HttpEntity httpEntity = new UrlEncodedFormEntity(list, "utf-8");
                httpPost.setEntity(httpEntity);
            }
            response = httpClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            if (HttpStatus.SC_OK == statusCode) {
                HttpEntity entity = response.getEntity();
                if (null != entity) {
                    String resStr = EntityUtils.toString(entity, charset);
                    return resStr;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != response)
                    response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * @Description: 获取get连接..
     * @Author: liuh
     * @Date: 2020/10/10
     */
    public static HttpGet getHttpGet(String sourceUrl, String url) {
        int agentIdx = RandomUtils.getRandomNumber(UserAgentConstant.AGENT_ARRS.length);
        HttpGet httpGet = new HttpGet(url);
        if (sourceUrl == null || sourceUrl.isEmpty()) {
            // 获取省级get请求
            httpGet.addHeader("Upgrade-Insecure-Requests", "1");
            httpGet.addHeader("User-Agent", UserAgentConstant.AGENT_ARRS[agentIdx]);
            return httpGet;
        }
//        httpGet.addHeader("Cookie", "_trs_uv=kg0fhpiw_6_dg7w; SF_cookie_1=37059734; _trs_ua_s_1=kg3gxr66_6_bqqf; wzws_cid=4b06a9af98b22fb93ac818f97258c3d5790f062eff4c0abe2910536136ccef8b08f6ebd86a5ec54c58422978e1452c205c7060d7fd6cc6f5149a62489d05650937722bf4ab738fbad3a01acf7b3c4d73");
        // 来源地址信息..
        httpGet.addHeader("Referer", sourceUrl);
        httpGet.addHeader("Upgrade-Insecure-Requests", "1");
        //TODO 通过配置文件动态获取
        httpGet.addHeader("User-Agent", UserAgentConstant.AGENT_ARRS[agentIdx]);
        return httpGet;
    }

    public static void main(String[] args) {
//        //设置代理IP、端口、协议（请分别替换）
//        HttpHost proxy = new HttpHost("221.131.158.246", 8888, "http");
//        //把代理设置到请求配置
//        RequestConfig defaultRequestConfig = RequestConfig.custom()
//                .setProxy(proxy)
//                .build();
//        //实例化CloseableHttpClient对象
//        CloseableHttpClient httpclient = HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig).build();
//        //访问目标地址
//        HttpGet httpGet = new HttpGet("http://www.baidu.com");
//        //请求返回
//        CloseableHttpResponse httpResp = null;
//        try {
//            httpResp = httpclient.execute(httpGet);
//            int statusCode = httpResp.getStatusLine().getStatusCode();
//            if (statusCode == HttpStatus.SC_OK) {
//                System.out.println("成功");
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//        } finally {
//            if (httpResp != null) {
//                try {
//                    httpResp.close();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
//        }
    }

}
